import os
from wsgiref.util import FileWrapper

import pymongo
from django.http import JsonResponse
from django.http.response import StreamingHttpResponse
from django.shortcuts import render
from django.template import defaultfilters

from md.templatetags import myfilters
from md.util import mongo
from md.util import utils
from md.util.constants import FileType, FileStatus
from md.util.utils import Code, FileUtils


# 首页,全部文件
def home(request):
    collection = mongo.get_collection('md_file')
    cursor = collection.find({'file_parent': ''}).sort([('file_length', pymongo.ASCENDING), ('file_name', pymongo.ASCENDING)])
    files = list()
    # 将mongo的_id字段转换成id
    for file in list(cursor):
        f = dict(file)
        f['id'] = f.pop("_id")
        files.append(f)
    context = {'files': files}
    return render(request, "index.html", context)


def ajax_list_file(request):
    """ 请求文件列表 """
    file_parent = request.GET.get('file_parent', '')
    file_sort = request.GET.get('file_sort', None)
    keyword = request.GET.get('keyword', '')

    query = {}
    query.update({'file_parent': file_parent})
    keyword and query.update({'file_name': {'$regex': r'.*{0}.*'.format(keyword), '$options': 'i'}})
    sort = [('file_length', pymongo.ASCENDING)]
    file_sort and sort.append((file_sort, pymongo.ASCENDING))

    collec = mongo.get_collection('md_file')
    cursor = collec.find(query).sort(sort)
    files = list()
    for f in cursor:
        file = dict(f)
        file['id'] = file.pop('_id')
        file['file_icon'] = myfilters.file_ext_format(file.get('file_ext')) if file.get('file_type') == FileType.FILE else '#icon-folder-c'
        file['file_length'] = defaultfilters.filesizeformat(file.get('file_length')) if file.get('file_length') else '-'
        file['file_upload_date'] = myfilters.datetimeformat(file.get('file_upload_date'))
        files.append(file)

    # 查询当前目录的父目录ID
    prev = collec.find_one({'_id': file_parent}, {'_id': 0, 'file_parent': 1})
    prev_id = '' if not prev else prev.get('file_parent', '')
    result = {'prev': prev_id, 'files': files}
    return JsonResponse(utils.response_json(code=Code.success, data=result))


# ajax 上传文件
# noinspection PyBroadException
def upload_file(request):
    up_file = request.FILES.get('file', None)
    if up_file:
        try:
            file_parent = request.POST.get('file_parent', '')

            file_url = FileUtils.upload(request, 'file')
            # 增加记录到数据库
            doc = {
                '_id': mongo.get_hex_objectid(),
                'file_name': up_file.name,
                'file_length': up_file.size,
                'file_url': file_url,
                'file_ext': utils.get_file_ext(up_file.name),
                'file_type': FileType.FILE,
                'file_parent': file_parent,
                'file_upload_date': utils.get_cur_timestamp(),
                'file_status': FileStatus.ENABLED
            }
            mongo.get_collection("md_file").insert_one(doc)
            doc['file_icon'] = myfilters.file_ext_format(doc.get('file_ext', None))
            doc['file_length'] = defaultfilters.filesizeformat(doc.get('file_length'))
            doc['file_upload_date'] = myfilters.datetimeformat(doc.get('file_upload_date', 0))
            doc['id'] = doc.get("_id")
            doc.pop("_id")
            result = utils.response_json(Code.success, '上传成功', doc)
        except BaseException as e:
            print(e)
            result = utils.response_json(Code.failure, '文件上传异常')
    else:
        result = utils.response_json(Code.failure, '上传文件失败')
    return JsonResponse(result)


# 下载单个文件
def download_file(request):
    file_id = request.GET['file_id']
    file_item = mongo.get_collection("md_file").find_one({'_id': file_id}, {'file_name': 1, 'file_type': 1, 'file_url': 1})
    if file_item and file_item.get('file_type') == FileType.FILE:
        file_name = file_item.get('file_name', '')
        file_url = file_item.get('file_url', '')
        try:
            download_path = os.path.join(utils.get_root_path(), file_url)
            response = StreamingHttpResponse(FileWrapper(open(download_path, "rb")))
            response['Content-Type'] = 'application/octet-stream'
            response['Content-Disposition'] = u'attachment; filename={0}'.format(file_name).encode('utf8')  # utf8编码解决中文文件名无法显示
            return response
        except BaseException as e:
            return JsonResponse(utils.response_json(Code.failure, 'an error occured:' + str(e)))
    return JsonResponse({"msg": 'Download failure, may be the file source is not exists.'})


# 删除单个文件
def delete_file(request):
    file_id = request.POST.get('file_id', None)
    if file_id:
        try:
            # 根据文件ID查找到文件的路径,并删除数据记录
            file_do = mongo.get_collection("md_file").find_one_and_delete({'_id': file_id}, {'file_type': 1, 'file_url': 1})
            file_url = file_do.get('file_url')
            if file_url:  # 删除硬盘上的文件
                os.remove(os.path.join(utils.get_root_path(), file_url))
            result = utils.response_json(Code.success, '文件删除成功')
        except BaseException as e:
            print(e)
            result = utils.response_json(Code.failure, '炸')
    else:
        result = utils.response_json(Code.failure, '文件删除失败')
    return JsonResponse(result)


# 删除多个文件
def delete_files(request):
    file_ids = request.POST.get('file_ids', [])
    ids = file_ids.split(',')
    paths = []
    collec = mongo.get_collection("md_file")
    # 获取到所选文件的URL
    cursor = collec.find({'$or': [{'_id': {'$in': ids}}, {'file_parent': {'$in': ids}}]}, {'file_type': 1, 'file_url': 1})
    for c in cursor:
        path = c.get('file_url', '')
        path and paths.append(path)
    # 删除硬盘文件
    utils.remove_paths(paths)
    # 删除数据库中的记录
    collec.delete_many({'_id': {'$in': ids}})
    return JsonResponse(utils.response_json(Code.success, '删除成功'))


def add_folder(request):
    """ 新增文件夹 """
    folder_name = request.POST.get('folder_name', '')
    folder_parent = request.POST.get('folder_parent', '')

    # 校验文件夹是否已经存在
    collec = mongo.get_collection('md_file')
    count = collec.count({'file_name': {'$regex': '^{0}$'.format(folder_name), '$options': 'i'}, 'file_parent': folder_parent})
    if count > 0:
        return JsonResponse(utils.response_json(Code.failure, '文件夹已存在'))

    folder = dict({'_id': mongo.get_hex_objectid()})
    folder['file_name'] = folder_name
    folder['file_type'] = FileType.FOLDER
    folder['file_parent'] = folder_parent
    folder['file_upload_date'] = utils.get_cur_timestamp()
    folder['file_status'] = FileStatus.ENABLED
    collec.insert_one(folder)
    folder['file_upload_date'] = myfilters.datetimeformat(folder.get('file_upload_date'))
    folder['file_icon'] = '#icon-folder-c'
    folder['file_length'] = '-'
    folder['id'] = folder.pop('_id')
    return JsonResponse(utils.response_json(Code.success, '新建文件夹成功', folder))


def move_file(request):
    """ 移动文件/文件夹 """
    try:
        file_ids = request.POST.get('file_ids', '')
        ids = file_ids.split(',')
        target_folder_id = request.POST.get('target')
        mongo.get_collection('md_file').update({'_id': {'$in': ids}}, {'$set': {'file_parent': target_folder_id}}, multi=True)
        return JsonResponse(utils.response_json(Code.success))
    except BaseException as e:
        print(e)
        return JsonResponse(utils.response_json(Code.failure, '操作异常'))


def get_child_folder(request):
    """ 根据父文件夹ID,查询子文件夹 """
    parent = request.GET.get('parent', None)
    cursor = mongo.get_collection('md_file').find({'file_parent': parent, 'file_type': FileType.FOLDER}, {'_id': 1, 'file_name': 1})
    files = list()
    for f in cursor:
        f['id'] = f.pop('_id')
        files.append(f)
    return JsonResponse(utils.response_json(Code.success, data=files))


def share_file(request):
    """ 分享文件 """
    file_ids = request.POST.get("file_ids", '').split(',')
    is_encrypt = int(request.POST.get('is_encrypt', 0))
    # 加密分享,生成随机密码
    password = utils.get_random_str(4) if is_encrypt else None
    share_id = utils.get_random_str()
    share = {
        '_id': share_id,
        'is_encrypt': is_encrypt,
        'password': password,
        'files': file_ids,
        'share_date': utils.get_cur_timestamp()
    }
    mongo.get_collection('md_share').insert_one(share)
    host = request.get_host()
    port = request.get_port()
    host = '{0}{1}'.format(host, ':{0}'.format(port) if port != '80' else '')
    data = {
        'share_url': '{0}/s/{1}'.format(host, share.get('_id')),
        'password': share.get('password')
    }
    return JsonResponse(utils.response_json(Code.success, data=data))


def get_share_file(request):
    """ 查看分享 """
    request_path = request.get_full_path()
    share_id = request_path.split('/')[2]
    share = mongo.get_collection('md_share').find_one({'_id': share_id})
    file_list = []
    if share:
        is_encrypt = share.get('is_encrypt', 0)
        if is_encrypt:
            # 如果该分享是私密分享,则转发到输入密码页面
            context = {'share_id': share.get('_id')}
            return render(request, 's-pwd.html', context)
        else:
            files = share.get('files')
            cursors = mongo.get_collection('md_file').find({'_id': {'$in': files}})
            for file in cursors:
                file['id'] = file.pop('_id')
                file_list.append(file)

    context = {'file_list': file_list}
    return render(request, "share.html", context)


def get_encrypt_share_file(request):
    """ 查看加密分享 """
    request_path = request.get_full_path()
    s = request_path.split('/')
    print(s)
    share_id = s[2]
    password = s[3]
    share = mongo.get_collection('md_share').find_one({'_id': share_id, 'password': password})
    file_list = []
    if share:
        files = share.get('files')
        cursors = mongo.get_collection('md_file').find({'_id': {'$in': files}})
        for file in cursors:
            file['id'] = file.pop('_id')
            file_list.append(file)
    context = {'file_list': file_list}
    return render(request, "share.html", context)


def delete_share(request):
    """ 取消分享 """
    share_ids = request.GET.get('share_ids', '').split(',')
    mongo.get_collection('md_share').delete_many({'_id': {'$in': share_ids}})
    return JsonResponse(utils.response_json(msg='删除成功'))


def valid_share_pwd(request):
    """ 验证分享密码 """
    password = request.POST.get('password')
    _id = request.POST.get('share_id')
    count = mongo.get_collection('md_share').count({'_id': _id, 'password': password});
    result = utils.response_json(Code.success) if count else utils.response_json(Code.failure, '密码错误')
    return JsonResponse(result)


def get_share_list(request):
    """ 查询分享列表 """
    shares = []
    port = request.get_port()
    host = request.get_host()
    base_path = host if port == '80' else '{0}:{1}'.format(host, port)

    cursors = mongo.get_collection('md_share').find()
    file_colle = mongo.get_collection('md_file')
    for share in cursors:
        files = share.pop('files')
        if len(files):
            file = file_colle.find_one({'_id': files[0]}, {'file_name': 1})
            if file:
                share['desc'] = file.get('file_name') if len(files) < 2 else '{0}, 等文件'.format(file.get('file_name'))

        share['id'] = share.pop('_id')
        share['share_date'] = myfilters.datetimeformat(share.get('share_date'))
        clink = '{0}/s/{1}'.format(base_path, share.get('id'));
        share['clink'] = '链接:{0} 密码:{1}'.format(clink, share.get('password')) if int(share.get('is_encrypt')) else clink
        shares.append(share)
    data = {'shares': shares}
    return JsonResponse(utils.response_json(Code.success, data=data))